package com.github.hiling.common.filter;

import com.alibaba.fastjson2.JSON;
import com.github.hiling.common.annotation.NoAuth;
import com.github.hiling.common.constant.ErrorMessage;
import com.github.hiling.common.exception.ExceptionResult;
import com.github.hiling.common.oauth.JwtUtils;
import com.github.hiling.common.utils.RequestUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author wanghailiang
 */
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Object handler) throws Exception {

        String requestUrl = RequestUtils.getRequestUrl(request);

        //拦截 vue options请求
        if (HttpMethod.OPTIONS.name().equals(request.getMethod())) {
            log.info("options return, URL:{}", requestUrl);
            return true;
        }

        if (!handler.getClass().isAssignableFrom(HandlerMethod.class)) {
            log.info("class return, URL:{}", requestUrl);
            return true;
        }

        // 通过客户端访问时，使用keys认证
        // 获取当前访问的class和方法
        final HandlerMethod handlerMethod = (HandlerMethod) handler;
        final Method method = handlerMethod.getMethod();
        final Class<?> clazz = method.getDeclaringClass();

        //方法或者类是否有NoAuth注解，如果有注解则不验证登录
        if (clazz.isAnnotationPresent(NoAuth.class) || method.isAnnotationPresent(NoAuth.class)) {
            log.debug("NoAuth return, method: {} clazz{}", method.isAnnotationPresent(NoAuth.class), clazz.isAnnotationPresent(NoAuth.class));
            return true;
        }

        String jwtToken = RequestUtils.getRequestData(request, "jwtToken");

        if (StringUtils.hasText(jwtToken)) {
            Map<String, Object> claims = JwtUtils.parserJavaWebToken(jwtToken);
            if (claims == null) {
                log.info("jwtToken is error, URL:{}", requestUrl);
                writeResponse(request, response, ErrorMessage.TOKEN_ERROR);
                return false;
            }
            return true;
        } else {
            log.info("jwtToken is empty, URL:{}", requestUrl);
            writeResponse(request, response, ErrorMessage.TOKEN_EMPTY);
            return false;
        }
    }

    private void writeResponse(HttpServletRequest request,HttpServletResponse response, ErrorMessage errorCode)
            throws IOException {
        ExceptionResult businessException = new ExceptionResult(errorCode.value(), errorCode.getMessage(),"AuthInterceptor", RequestUtils.getRequestUrl(request));
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().print(JSON.toJSONString(businessException));
        response.getWriter().flush();
        response.getWriter().close();
    }

    /**
     *
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 请求调用完成后回调方法，即在视图渲染完成后回调
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }

}

